package com.xbongbong.admin.help;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.admin.domain.entity.RaidersCorpEntity;
import com.xbongbong.admin.domain.entity.RaidersEntity;
import com.xbongbong.admin.domain.entity.ext.RaidersCorpEntityExt;
import com.xbongbong.admin.model.RaidersCorpModel;
import com.xbongbong.admin.model.RaidersModel;
import com.xbongbong.admin.pojo.PointPojo;
import com.xbongbong.admin.pojo.PointUrlBasePojo;
import com.xbongbong.admin.pojo.StepInfoPojo;
import com.xbongbong.admin.pojo.vo.RaidersVO;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.domain.entity.PaasAppEntity;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.model.PaasAppModel;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.ReflectHelper;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.constant.RaidersConstant;
import com.xbongbong.pro.constant.SymbolConstant;
import com.xbongbong.pro.enums.AccessLinkEnum;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.RaidersErrorCodeEnum;
import com.xbongbong.pro.enums.raiders.enums.RaidersFinishEnum;
import com.xbongbong.pro.enums.raiders.enums.RaidersGroupRecommendEnum;
import com.xbongbong.pro.enums.raiders.enums.RaidersLockEnum;
import com.xbongbong.pro.enums.raiders.enums.RaidersPointChildEnum;
import com.xbongbong.pro.enums.raiders.enums.RaidersPointParentEnum;
import com.xbongbong.pro.enums.raiders.enums.RaidersPublishEnum;
import com.xbongbong.pro.enums.raiders.enums.RaidersStageEnum;
import com.xbongbong.pro.enums.raiders.enums.RaidersStepEnum;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.sys.domain.entity.CompanyConfigEntity;
import com.xbongbong.sys.domain.entity.FeeCompanyEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.FeeCompanyModel;
import com.xbongbong.sys.model.UserModel;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * @author zcp
 * @version v1.0
 * @date 19/9/24 024 15:32
 * @update 19/9/24 024 15:32
 * @since v1.0
 */
@Component
public class RaidersHelp {

    @Resource
    private FeeCompanyModel feeCompanyModel;
    @Resource
    private RaidersModel raidersModel;
    @Resource
    private RaidersCorpModel raidersCorpModel;
    @Resource
    private PaasAppModel paasAppModel;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private UserModel userModel;

    /**
     * 判断该公司是否属于白名单公司
     * 白名单内的公司，则可以看到未发布的攻略，且不限制阶段（套餐），但是私有攻略还想需要推荐给这个公司才能查看使用
     * @return java.util.Set<java.lang.String>
     * @author zcp
     * @date 19/9/30 030 17:00
     * @update 19/9/30 030 17:00
     * @since v1.0
     * @version v1.0
     */
    public boolean checkWhite(String corpid) {
        /**
          建议做成缓存缓存方式：
         （1）因为白名单其实就我们自己的公司及测试用的几个，没必要每次读库
         （2）正式上线后，一般不会变更白名单配置，用缓存方式能省一些数据库查询（detail等接口除了获取详情用到白名单，处理解锁获取分组内攻略列表也用到白名单，如果缓存的话就避免每次多查两次）
         （3）每次白名单更新，则重置缓存即可
         */
        Set<String> whiteSet = new HashSet<>();
        String alias = CompanyConfigEnum.RAIDERS_WHITE.getAlias();
        String value = paasRedisHelper.getValue(RedisConstant.KEY_COMPANY_CONFIG, alias);
        if (value == null) {
            //读出白名单配置
            CompanyConfigEntity companyConfig = companyConfigModel.getByConfigAlias(alias, RaidersConstant.RAIDERS_WHITE_CORPID);
            if (companyConfig != null) {
                whiteSet.addAll(JsonHelperUtil.parseArray(companyConfig.getConfigValue(), String.class));
                //存入缓存
                paasRedisHelper.setValue(RedisConstant.KEY_COMPANY_CONFIG, alias, JSONArray.toJSONString(whiteSet), TimeConstant.SECONDS_PER_WEEK);
            }
        } else {
            whiteSet.addAll(JsonHelperUtil.parseArray(value, String.class));
        }
        return whiteSet.contains(corpid);
    }

    /**
     * 获取攻略list，且已经过滤一些条件（如下），未过滤公司，推荐分组需额外处理（只获取推荐给自己公司的）
     * （1）未删除，已发布；
     * （2）阶段（与当前公司套餐挂钩），通过raidersHelp.stageCodeIn(corpid)方法得到
     * （3）角色权限过滤，如果未设置角色权限，则默认所有角色权限都可以看到
     * @param corpid 公司id
     * @param groupId 分组id
     * @param loginUser 登录员工
     * @return java.util.List<com.xbongbong.admin.domain.entity.RaidersEntity>
     * @author zcp
     * @date 19/9/27 027 20:19
     * @update 19/9/27 027 20:19
     * @since v1.0
     * @version v1.0
     */
    public List<RaidersEntity> getRaidersList4Filter(String corpid, Long groupId, UserVO loginUser) {
        List<Long> groupIdIn = Collections.singletonList(groupId);
        return getRaidersList4Filter(corpid, groupIdIn, loginUser);
    }

    /**
     * 获取攻略list，且已经过滤一些条件（如下），未过滤公司，推荐分组需额外处理（只获取推荐给自己公司的）
     * （1）未删除，已发布；
     * （2）阶段（与当前公司套餐挂钩），通过raidersHelp.stageCodeIn(corpid)方法得到
     * （3）角色权限过滤，如果未设置角色权限，则默认所有角色权限都可以看到
     * @param corpid 公司id
     * @param groupIdIn 分组id数组
     * @param loginUser 登录员工
     * @return java.util.List<com.xbongbong.admin.domain.entity.RaidersEntity>
     * @author zcp
     * @date 19/9/27 027 20:13
     * @update 19/9/27 027 20:13
     * @since v1.0
     * @version v1.0
     */
    public List<RaidersEntity> getRaidersList4Filter(String corpid, List<Long> groupIdIn, UserVO loginUser) {
        //判断该公司是否属于白名单公司
        boolean white = checkWhite(corpid);
        //获取当前公司的套餐阶段
        List<Integer> stageCodeIn = stageCodeIn(corpid);
        UserEntity userEntity = new UserEntity();
        BeanUtil.copyProperties(loginUser, userEntity);
        Integer dataPermission = userModel.getDataPermission(userEntity, true);
        List<RaidersEntity> list = raidersModel.getRaidersList4Filter(white, groupIdIn, stageCodeIn, dataPermission);
        return list;
    }

    /**
     * 判断攻略是否是私有分组，私有分组按照推荐顺序排序
     * 如果是白名单公司，则不用区分是否是私有分组
     * @param groupId
     * @return boolean
     * @author zcp
     * @date 19/9/29 029 11:18
     * @update 19/9/29 029 11:18
     * @since v1.0
     * @version v1.0
     */
    public boolean checkRecommend(Long groupId) {
        return Objects.equals(groupId, RaidersGroupRecommendEnum.RECOMMEND.getId());
    }

    /**
     * 获取攻略实体，并过滤掉已删除、未发布的攻略
     * @param corpid 公司id
     * @param raidersId 攻略id
     * @param operateMsg 错误提示操作
     * @return com.xbongbong.admin.domain.entity.RaidersEntity
     * @throws XbbException
     * @author zcp
     * @date 19/9/29 029 19:50
     * @update 19/9/29 029 19:50
     * @since v1.0
     * @version v1.0
     */
    public RaidersEntity getRaidersEntity(String corpid, Long raidersId, String operateMsg) throws XbbException {
        RaidersEntity entity = raidersModel.getByKey(raidersId);
        if (entity == null || Objects.equals(entity.getDel(), 1)) {
            throw new XbbException(RaidersErrorCodeEnum.API_ERROR_800005, RaidersErrorCodeEnum.API_ERROR_800005.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.RAIDERS));
        }
        //判断该公司是否属于白名单公司
        boolean white = checkWhite(corpid);
        //不在白名单内，且攻略未发布，则无法查看该攻略
        if (!white && Objects.equals(entity.getPublish(), RaidersPublishEnum.UN_PUBLISH.getCode())) {
            throw new XbbException(RaidersErrorCodeEnum.API_ERROR_800013, String.format(RaidersErrorCodeEnum.API_ERROR_800013.getMsg(), operateMsg));
        }
        return entity;
    }

    /**
     * 获取攻略公司对应关系，如果不存在，或者lock锁定中，则不能查看攻略
     * @param corpid 公司id
     * @param raidersId 攻略id
     * @return com.xbongbong.admin.domain.entity.RaidersCorpEntity
     * @throws XbbException
     * @author zcp
     * @date 19/9/30 030 19:22
     * @update 19/9/30 030 19:22
     * @since v1.0
     * @version v1.0
     */
    public RaidersCorpEntity getRaidersCorpEntity(String corpid, Long raidersId) throws XbbException {
        RaidersCorpEntity raidersCorpEntity = raidersCorpModel.getByRaidersId(raidersId, corpid);
        if (raidersCorpEntity == null || Objects.equals(raidersCorpEntity.getLock(), RaidersLockEnum.FINISH_PRE_STEP.getCode())) {
            throw new XbbException(RaidersErrorCodeEnum.API_ERROR_800016, RaidersErrorCodeEnum.API_ERROR_800016.getMsg());
        }
        return raidersCorpEntity;
    }

    /**
     * 判断步骤（预览、视频介绍、实操等）是否开启
     * @param step 步骤
     * @return boolean true 该步骤未开启，false 已开启
     * @author zcp
     * @date 19/10/11 011 17:22
     * @update 19/10/11 011 17:22
     * @since v1.0
     * @version v1.0
     */
    public boolean checkStepClose(JSONObject step) {
        //true 该步骤未开启，false 已开启
        return step == null || Objects.equals(step.getInteger("enable"), 0);
    }

    /**
     * 得到攻略id-攻略vo（返回前端的list内的vo）对应关系map
     * @param list 该分组内的攻略list
     * @param corpRaidersMap 攻略id-攻略公司关系实体
     * @param corpRaidersMap pointKey-该功能点信息pojo（此pojo内只置入了功能点的icon和color）
     * @return java.util.Map<java.lang.Long,com.xbongbong.admin.pojo.vo.RaidersVO> 返回的map是有序的LinkedHashMap
     * @author zcp
     * @date 19/9/25 025 20:51
     * @update 19/9/25 025 20:51
     * @since v1.0
     * @version v1.0
     */
    public Map<Long, RaidersVO> getRaidersVoMap(List<RaidersEntity> list, Map<Long, RaidersCorpEntity> corpRaidersMap, Map<Integer, PointPojo> raidersPointMap) {
        //攻略id-攻略vo（先放入map，后续可能需要更新该攻略的point、lock、unLockTip等-未解锁时，需要算该攻略所有解锁的公司数）
        Map<Long, RaidersVO> voMap = new LinkedHashMap<>();
        //未解锁的攻略，需要计算已经解锁的公司数
        Set<Long> unLockIdIn = new HashSet<>();
        for (int i = 0; i < list.size(); i++) {
            RaidersEntity entity = list.get(i);
            RaidersVO raidersVO = new RaidersVO();
            BeanUtil.copyProperties(entity, raidersVO);
            Long id = entity.getId();
            //判断是否要解锁、得到该公司该攻略的积分
            RaidersCorpEntity raidersCorpEntity = corpRaidersMap.get(id);
            int lockFlag = checkLock4List(entity.getLock(), raidersCorpEntity, i);
            if (i > 0 && Objects.equals(RaidersLockEnum.FINISH_PRE_STEP.getCode(), lockFlag)) {
                //如果攻略还是锁定，则读取上一步是否已经解锁
                Long lastId = list.get(i - 1).getId();
                //上一步
                RaidersCorpEntity lastCorp = corpRaidersMap.get(lastId);
                if (lastCorp != null && Objects.equals(RaidersFinishEnum.FINISH.getCode(), lastCorp.getFinish())) {
                    lockFlag = RaidersLockEnum.UN_LOCK.getCode();
                }
            }
            raidersVO.setLock(lockFlag);
            if (Objects.equals(lockFlag, RaidersLockEnum.FINISH_PRE_STEP.getCode())) {
                //锁定，则获取已经解锁的公司数
                unLockIdIn.add(id);
            } else if (raidersCorpEntity != null) {
                raidersVO.setScored(raidersCorpEntity.getTotalScore());
                raidersVO.setFinish(raidersCorpEntity.getFinish());
            }
            //处理功能点图标
            List<PointPojo> point = JsonHelperUtil.parseArray(JSONArray.toJSONString(entity.getPoint()), PointPojo.class);
            for (PointPojo pointPojo : point) {
                PointPojo info = raidersPointMap.get(pointPojo.getPointKey());
                if (info == null) {
                    continue;
                }
                BeanUtil.copyProperties(info, pointPojo, true);
            }
            raidersVO.setPoint(point);
            voMap.put(id, raidersVO);
        }
        //处理未解锁时的情况，并返回
        return handleUnLockTip(voMap, unLockIdIn);
    }
    /**
     * 处理功能点的name、icon和color，并得到pointKey和PointPojo的对应关系map
     * 注：次方法把功能点对应的name、icon和color塞入进PointPojo内
     * @param pointKeySet
     * @return java.util.Map<java.lang.Integer,com.xbongbong.admin.pojo.PointPojo>
     * @author zcp
     * @date 19/9/26 026 22:41
     * @update 19/9/26 026 22:41
     * @since v1.0
     * @version v1.0
     */
    public Map<Integer, PointPojo> handlePoint(Set<Integer> pointKeySet){
        //pointKey-该功能点信息pojo（此pojo内只置入了功能点的icon和color）
        Map<Integer, PointPojo> keyPointMap = new HashMap<>(pointKeySet.size());
        for (RaidersPointChildEnum cache : RaidersPointChildEnum.values()) {
            if (pointKeySet.size() == 0) {
                break;
            }
            if (!pointKeySet.contains(cache.getPointKey())) {
                continue;
            }
            pointKeySet.remove(cache.getPointKey());
            AccessLinkEnum iconColor = cache.getIconColor();
            PointPojo pointPojo = new PointPojo(cache.getName(), iconColor.getIcon(), iconColor.getColor());
            keyPointMap.put(cache.getPointKey(), pointPojo);
        }
        return keyPointMap;
    }
    /**
     * 处理功能点url需要的基础信息
     * @param corpid 公司id
     * @param pointKeySet 功能点的pointKey集合
     * @return java.util.Map<java.lang.Integer,com.xbongbong.admin.pojo.PointUrlBasePojo>
     * @author zcp
     * @date 19/9/30 030 15:47
     * @update 19/9/30 030 15:47
     * @since v1.0
     * @version v1.0
     */
    public Map<Integer, PointUrlBasePojo> handlePointUrlBasePojo(String corpid, Set<Integer> pointKeySet) {
        //功能点pointKey-该功能点选中的应用/菜单跳转需要的subBusinessType等信息
        Map<Integer, PointUrlBasePojo> urlBasePojoMap = new HashMap<>(pointKeySet.size());
        //应用alias集合
        Set<String> appAliasSet = new HashSet<>();
        //功能点alias-功能点pointKey
        Map<String, Integer> aliasKeyMap = new HashMap<>(pointKeySet.size());
        for (RaidersPointChildEnum cache : RaidersPointChildEnum.values()) {
            if (pointKeySet.size() == 0) {
                break;
            }
            Integer pointKey = cache.getPointKey();
            if (!pointKeySet.contains(pointKey)) {
                continue;
            }
            pointKeySet.remove(cache.getPointKey());
            PointUrlBasePojo pointUrlBasePojo = new PointUrlBasePojo();
            //baseUrl
            String baseUrl = cache.getAccessLinkEnum().getUrl();
            pointUrlBasePojo.setBaseUrl(baseUrl);
            //subBusinessType
            String alias = cache.getAlias();
            RaidersPointParentEnum parentEnum = cache.getParentEnum();
            if (Objects.equals(parentEnum.getType(), 1)) {
                XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByAlias(alias);
                if (xbbRefTypeEnum == null) {
                    continue;
                }
                pointUrlBasePojo.setSubBusinessType(xbbRefTypeEnum.getCode());
            } else if (Objects.equals(parentEnum.getType(), 2)) {
                //图表中心，无需设置subBusinessType
            } else if (Objects.equals(parentEnum.getType(), 3)) {
                //表单模板、流程设置、组织权限需要获取appId
                appAliasSet.add(alias);
                aliasKeyMap.put(alias, pointKey);
            }
            urlBasePojoMap.put(pointKey, pointUrlBasePojo);
        }
        if (appAliasSet.size() > 0) {
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put(StringConstant.CORPID, corpid);
            param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
            param.put("columns", "corpid,alias,id");
            param.put("aliasIn", appAliasSet);
            List<PaasAppEntity> appList = paasAppModel.findEntitys(param);
            for (PaasAppEntity paasAppEntity : appList) {
                Integer pointKey = aliasKeyMap.get(paasAppEntity.getAlias());
                PointUrlBasePojo pointUrlBasePojo = urlBasePojoMap.get(pointKey);
                pointUrlBasePojo.setAppId(paasAppEntity.getId());
            }
        }
        return urlBasePojoMap;
    }
    
    /**
     * 得到功能点的跳转链接
     * @param pointUrlBasePojo
     * @return java.lang.String
     * @author zcp
     * @date 19/9/30 030 16:21
     * @update 19/9/30 030 16:21
     * @since v1.0
     * @version v1.0
     */
    public String getPointUrl(PointUrlBasePojo pointUrlBasePojo) {
        if (pointUrlBasePojo == null) {
            return "";
        }
        StringBuilder url = new StringBuilder();
        //拼接baseUrl、saasMark
        url.append(pointUrlBasePojo.getBaseUrl()).append(SymbolConstant.QUESTION_MARK_ENGLISH).append("saasMark=").append(pointUrlBasePojo.getSaasMark());
        if (pointUrlBasePojo.getSubBusinessType() != null) {
            url.append("&subBusinessType=").append(pointUrlBasePojo.getSubBusinessType());
        }
        if (pointUrlBasePojo.getAppId() != null) {
            url.append("&appId=").append(pointUrlBasePojo.getAppId());
        }
        return url.toString();
    }

    /**
     * 获取功能点标题
     * @param pointArray 攻略的功能点枚举
     * @param pointKey 功能点pointKey
     * @return java.lang.String
     * @author zcp
     * @date 19/10/17 017 22:10
     * @update 19/10/17 017 22:10
     * @since v1.0
     * @version v1.0
     */
    public String getPointTitle(JSONArray pointArray, int pointKey) {
        String title = null;
        for (int i = 0; i < pointArray.size(); i++) {
            JSONObject itemJSON = pointArray.getJSONObject(i);
            if (Objects.equals(itemJSON.getIntValue("pointKey"), pointKey)) {
                title = itemJSON.getString("title");
                break;
            }
        }
        if (title == null) {
            //如果空，则读取枚举默认的名称
            title = RaidersPointChildEnum.getByPointKey(pointKey).getName();
        }
        return title;
    }

    /**
     * 处理raiders_corp中的finish字段
     *
     * @param raiders raiders
     * @param raidersCorp raiders_corp
     * @param stepScoreArray raiders_corp中获得的步骤数组
     * @return boolean true更改了raidersCorp的finish字段，false 未更改finish字段
     * @author 徐俊杰
     * @date 2019/10/15 14:49
     * @update 2019/10/17 by zcp 从RaidersCorpServiceImpl类内移入该help类，并优化逻辑
     * @since v1.0
     */
    public boolean disposeRaidersFinish(RaidersEntity raiders, RaidersCorpEntity raidersCorp, JSONArray stepScoreArray) {
        //从raiders中获取已开启的攻略步骤列表
        List<String> enableStepList = new ArrayList<>();
        List<String> stepList = RaidersStepEnum.getAllStep();
        for (String step : stepList) {
            JSONObject stepJSON = (JSONObject) ReflectHelper.valueGet(raiders, step);
            if (checkStepClose(stepJSON)) {
                continue;
            }
            enableStepList.add(step);
        }
        List<String> finishStepList = new ArrayList<>();
        /**
         * 判断所有在raiders_corp中已存在的step是否包含raiders中所有enable的step：首先关联关系表要有该步骤
         * 判断所有在raiders_corp中已存在的step的finish都为1：该步骤finish是完成状态
         */
        boolean hasFinish = false;
        for (int i = 0; i < stepScoreArray.size(); i++) {
            JSONObject stepScoreJSON = stepScoreArray.getJSONObject(i);
            StepInfoPojo stepInfoPojo = JSONObject.toJavaObject(stepScoreJSON, StepInfoPojo.class);
            String step = stepInfoPojo.getStep();
            if (enableStepList.contains(step)) {
                Integer finish = stepInfoPojo.getFinish();
                if (Objects.equals(finish, RaidersFinishEnum.FINISH.getCode())) {
                    finishStepList.add(step);
                    hasFinish = true;
                }
            }
        }
        Integer finish = raidersCorp.getFinish();
        //enableStepList是finishStepList的子集
        if (finishStepList.containsAll(enableStepList)) {
            finish = RaidersFinishEnum.FINISH.getCode();
        } else if (hasFinish) {
            finish = RaidersFinishEnum.FINISH_PART.getCode();
        }  else {
            finish = RaidersFinishEnum.FINISH_UN.getCode();
        }
        //处理finish值
        if (!Objects.equals(finish, raidersCorp.getFinish())) {
            raidersCorp.setFinish(finish);
            return true;
        }
        return false;
    }

    /**
     * 计算实操停留时长
     * @param startTime
     * @return java.lang.Integer
     * @author zcp
     * @date 19/9/30 030 11:03
     * @update 19/9/30 030 11:03
     * @since v1.0
     * @version v1.0
     */
    public Integer handleStaySeconds(Long startTime) {
        Integer seconds = 0;
        if (startTime != null && startTime > 0) {
            Long now = DateUtil.getNow();
            seconds = (int)(now - startTime);
        }
        return seconds;
    }

    /**
     * 点击攻略时，判断该公司该攻略是否解锁
     * @param lock 攻略本身的lock方式 1已经解锁，2未解锁
     * @param index 当前攻略在该分组攻略索引，私有分组时，需要特殊处理该值：要按照推荐给这个公司的顺序
     * @param raidersCorpEntity 攻略公司关系实体
     * @param lastCorp 上一步的攻略公司关系
     * @param lastRaiders 上一步的攻略实体
     * @return int 1已经解锁，2未解锁
     * @author zcp
     * @date 19/9/25 025 15:14
     * @update 19/9/25 025 15:14
     * @since v1.0
     * @version v1.0
     */
    public int checkLock4Through(Integer lock, int index, RaidersCorpEntity raidersCorpEntity, RaidersCorpEntity lastCorp, RaidersEntity lastRaiders) {
        //@see RaidersLockEnum 1已经解锁，2未解锁
        int lockFlag;
        RaidersLockEnum raidersLockEnum = RaidersLockEnum.getByCode(lock);
        switch (raidersLockEnum) {
            case UN_LOCK:
                //攻略本身无需解锁
                lockFlag = raidersLockEnum.getCode();
                break;
            case FINISH_PRE_STEP:
                //完成上一步解锁，与default一同处理
            default:
                if (raidersCorpEntity == null) {
                    /*
                     1已经解锁，2未解锁：
                     （1）该攻略不是“无需解锁”方式
                     （2）该公司还没有攻略关联关系实体
                     （3）index = 0，则为第一个攻略，标为解锁状态；index != 0，不是分组内的第一个攻略，则根据攻略自身的解锁状态确定
                     */
                    lockFlag = (index == 0) ? RaidersLockEnum.UN_LOCK.getCode() : lock;
                } else {
                    /*
                     1已经解锁，2未解锁：
                     （1）关联关系内如果已解锁或者当前index=0，即是分组第一个攻略，则lockFlag直接为false，即不锁定；
                     （2）关联关系锁定，但是上一个
                     */
                    boolean flag = index == 0 || Objects.equals(raidersCorpEntity.getLock(), RaidersLockEnum.UN_LOCK.getCode());
                    if (flag) {
                        lockFlag = RaidersLockEnum.UN_LOCK.getCode();
                    } else {
                        /**
                         如果锁定，再获取上一步
                         （1）判断上一步攻略总分是否为0，如果总分为0，则说明上一步没有分值可得，则此时只要上一步的攻略公司关系存在则该步骤即解锁（不存在需先了解上一步）
                         （2）上一步有分值，则判断上一步是否已完成
                         */
                        flag = lastRaiders != null && lastRaiders.getTotalScore() == 0 && lastCorp != null;
                        if (flag) {
                            lockFlag = RaidersLockEnum.UN_LOCK.getCode();
                        } else {
                            if (lastCorp != null && Objects.equals(lastCorp.getFinish(), 1)) {
                                //上一步（上一个攻略）该公司已完成，则这一步可以解锁
                                lockFlag = RaidersLockEnum.UN_LOCK.getCode();
                            } else {
                                //否则依赖攻略本身的状态
                                lockFlag = lock;
                            }
                        }
                    }
                }
                break;
        }
        return lockFlag;
    }

    /**
     * 分组内攻略，判断该公司该攻略是否解锁
     * @param lock 攻略的lock方式 1已经解锁，2未解锁
     * @param raidersCorpEntity 攻略公司关系实体
     * @param index 当前攻略在该分组攻略索引
     * @return int 1已经解锁，2未解锁
     * @author zcp
     * @date 19/9/25 025 20:15
     * @update 19/9/25 025 20:15
     * @since v1.0
     * @version v1.0
     */
    private int checkLock4List(Integer lock, RaidersCorpEntity raidersCorpEntity, int index){
        if (index == 0) {
            //第一个攻略，默认解锁
            return RaidersLockEnum.UN_LOCK.getCode();
        }
        //公司攻略未开始，或者攻略本身不需要解锁，使用攻略本身的解锁状态
        if (raidersCorpEntity == null || Objects.equals(RaidersLockEnum.UN_LOCK.getCode(), lock)) {
            return lock;
        }
        //否则直接使用关联关系内的解锁状态
        return raidersCorpEntity.getLock();
    }

    /**
     * 根据套餐情况，得到能查看的攻略阶段code list，规则如下：
     * （1）now < startTime 未到套餐时间，只有未限制阶段
     * （2）now >= expireTime 预计到期，则包含所有阶段(expireTime = endTime - TimeConstant.SECONDS_PER_MONTH
     * （3）now - startTime 大于半年（6个月时间），包含购买半年及之前的所有阶段，以此类推
     *
     * @param corpid 公司id
     * @return java.util.List<java.lang.Integer>
     * @author zcp
     * @date 19/9/24 024 17:25
     * @update 19/9/24 024 17:25
     * @version v1.0
     * @since v1.0
     */
    private List<Integer> stageCodeIn(String corpid) {
        FeeCompanyEntity feeCompany = feeCompanyModel.getNowFeeCompany(corpid);
        if (feeCompany == null || Objects.equals(feeCompany.getIsPay(), 0)) {
            //套餐不存在或者未付费，则只能使用未限制阶段的攻略
            return Arrays.asList(RaidersStageEnum.UN_LIMIT.getCode());
        }
        Long startTime = feeCompany.getStartTime();
        Long endTime = feeCompany.getEndTime();
        Long now = DateUtil.getNow();
        List<Integer> stageCodeIn = RaidersStageEnum.getStageList(startTime, endTime, now);
        return stageCodeIn;
    }

    /**
     * 当有未解锁的攻略时，则计算已经解锁的公司数，并处理成文字塞入RaidersVO
     * @param voMap 攻略id-攻略vo
     * @param unLockIdIn 未解锁的攻略，需要计算已经解锁的公司数
     * @return java.util.Map<java.lang.Long,com.xbongbong.admin.pojo.vo.RaidersVO>
     * @author zcp
     * @date 19/9/25 025 21:41
     * @update 19/9/25 025 21:41
     * @since v1.0
     * @version v1.0
     */
    private Map<Long, RaidersVO> handleUnLockTip(Map<Long, RaidersVO> voMap, Set<Long> unLockIdIn) {
        if (unLockIdIn.size() > 0) {
            //计算使用该攻略的公司数
            List<RaidersCorpEntityExt> unLockCorpCountList = raidersCorpModel.getUnLockCorpCount(unLockIdIn);
            //攻略id-解锁该攻略的公司数
            Map<Long, Integer> countMap = new HashMap<>(unLockCorpCountList.size());
            for (RaidersCorpEntityExt entityExt : unLockCorpCountList) {
                countMap.put(entityExt.getRaidersId(), entityExt.getCorpCount());
            }
            for (Long raidersId : unLockIdIn) {
                int count = countMap.getOrDefault(raidersId, 0);
                RaidersVO raidersVO = voMap.get(raidersId);
                raidersVO.setUnLock(count + "");
            }
        }
        return voMap;
    }
}
